package de.fzi.kasma.learner.path;

/**
 * Copyright (C) 2009 G�nter Ladwig (gla at aifb.uni-karlsruhe.de)
 * 
 * This file is part of the graphindex project.
 *
 * graphindex is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License, version 2
 * as published by the Free Software Foundation.
 * 
 * graphindex is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with graphindex.  If not, see <http://www.gnu.org/licenses/>.
 */

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.jgrapht.graph.DirectedMultigraph;
import org.semanticweb.yars.nx.namespace.RDF;

public class PathGraph extends DirectedMultigraph<PNode, PathEdge> implements
		Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -1356274835706353638L;

	public PathGraph() {
		super(PathEdge.class);
	}

	public PathEdge addEdge(String src, String property, String trg) {
		return addEdge(new PNode(src), property, new PNode(trg));
	}

	public PathEdge addEdge(PNode src, String property, PNode trg) {
		if (!containsVertex(src))
			addVertex(src);
		else
			src = getNodeByLabel(src.getLabel());

		if (!containsVertex(trg))
			addVertex(trg);
		else
			trg = getNodeByLabel(trg.getLabel());

		PathEdge e = new PathEdge(src, trg, property, this);
		addEdge(src, trg, e);
		return e;
	}

	public PNode getNodeByLabel(String label) {
		for (PNode node : vertexSet())
			if (node.getLabel().equals(label))
				return node;
		return null;
	}

	public int edgeCount() {
		return edgeSet().size();
	}

	public int nodeCount() {
		return vertexSet().size();
	}

	public int degreeOf(PNode node) {
		return inDegreeOf(node) + outDegreeOf(node);
	}

	public Set<PNode> predecessors(PNode node) {
		Set<PNode> preds = new HashSet<PNode>();
		for (PathEdge e : incomingEdgesOf(node))
			preds.add(e.getSource());
		return preds;
	}

	public Set<PNode> successors(PNode node) {
		Set<PNode> preds = new HashSet<PNode>();
		for (PathEdge e : outgoingEdgesOf(node))
			preds.add(e.getTarget());
		return preds;
	}

	public PathGraph deepCopy() {
		PathGraph graph = new PathGraph();

		for (PathEdge e : edgeSet()) {
			graph.addEdge((PNode) e.getSource().clone(), e.getLabel(),
					(PNode) e.getTarget().clone());
		}

		return graph;
	}

	public List<PathEdge> getEdges(String prop) {
		Iterator<PathEdge> edges = this.edgeSet().iterator();
		List<PathEdge> result = new ArrayList<PathEdge>();
		while (edges.hasNext()) {
			PathEdge edge = edges.next();
			if (edge.getProperty().equals(prop))
				result.add(edge);
		}
		return result;
	}

	public boolean containsPattern(String type, String prop, boolean incoming,
			PathEdge edge) {
		Set<PathEdge> neighbours = null;
		if (incoming)
			neighbours = this.incomingEdgesOf(edge.getSource());
		else
			neighbours = this.outgoingEdgesOf(edge.getSource());

		for (Iterator<PathEdge> it = neighbours.iterator(); it.hasNext();) {

			PathEdge neig = it.next();
			if (neig.getProperty().equals(RDF.TYPE.toString())) {
				continue;
			}
			if (neig.getProperty().equals(prop)) {
				if (incoming) {
					if (this.containsEdge(neig.getSource().getLabel(), type)) {
						return true;
					}
				} else {
					if (this.containsEdge(neig.getTarget().getLabel(), type)) {
						return true;
					}

				}
			}
		}
		return false;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		PathGraph other = (PathGraph) obj;
		if (nodeCount() == other.nodeCount()) {
			if (edgeSet().equals(other.edgeSet())) {
				for (PathEdge e1 : edgeSet()) {
					for (PathEdge e2 : other.edgeSet()) {
						if (e1.equals(e2)) {
							return true;
						} else if (e1.weakEquals(e2)) {
							return true;
						}
					}
				}

			}
		}
		return false;

	}

	private boolean containsEdge(String x1, String x2) {
		PNode y1 = new PNode(x1);
		PNode y2 = new PNode(x2);

		if (this.getEdge(y1, y2) != null) {
			return true;
		}
		return false;
	}

}